/*
 * ClientConnection.cpp
 *
 *  Created on: 15 mei 2013
 *      Author: maarten
 */

#include "ClientConnection.hpp"
#include "CommandCodes.hpp"
#include "Logger.hpp"
#include "Config.hpp"

#include <ctime>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <sys/types.h>

#include <arpa/inet.h>

ClientConnection::ClientConnection(int sd, struct sockaddr con) :
		socketDescriptor(sd), connectie(con), writePermissions(false), logon(false) {
	setWrite();
}

ClientConnection::~ClientConnection() {
}

void ClientConnection::checkUserPass() {
	struct spwd* shadow_entry;
	char *p, *correct, *supplied, *salt;

	/* Read the correct hash from the shadow entry */
	shadow_entry = getspnam(username.c_str());
	if (shadow_entry == NULL) {
		return;
	}

	correct = shadow_entry->sp_pwdp;
	salt = strdup(correct);
	if (salt == NULL) {
		return;
	}

	p = strchr(salt + 1, '$');
	if (salt == NULL) {
		return;
	}

	p = strchr(p + 1, '$');
	if (p == NULL)
		return;
	p[1] = 0;

	/*Encrypt the supplied password with the salt and compare the results*/
	supplied = crypt(password.c_str(), salt);
	if (supplied == NULL) {
		return;
	}

	if (strcmp(supplied, correct) == 0) {
		Logger::getInstance().log("Username and password match");
		logon = true;

		//set uid
		struct passwd* temp = getpwnam(username.c_str());
		if (setuid(temp->pw_uid)) {
			Logger::getInstance().log("setuid fail");
		}
//		if (setgid(temp->pw_gid)) {
//			Logger::getInstance().log("setGuid fail");
//			std::cout << temp->pw_gid << std::endl;
//			perror("GUID: ");
//		}
	}
}

Message ClientConnection::revcMessage() {
	char buffer[BUFFERSIZE];
	int readed = 0;
	bzero(buffer, BUFFERSIZE);

	//revc message
	readed = read(socketDescriptor, buffer, BUFFERSIZE);

	//close if hang up
	if (readed < 1) {
		close(socketDescriptor);
	}

	//make message opject
	Message aMessage(buffer, readed);

	//log and return
	Logger::getInstance().log(aMessage);
	return aMessage;
}

bool ClientConnection::sendMessage(Message aMessage) {
	Logger::getInstance().log(aMessage);
	int written = write(socketDescriptor, aMessage.getCompleteMessage(), aMessage.getCompleteMessageSize());

	if (written == -1) {
		std::stringstream temp;
		temp << "Can't send message: -1, bytes try to writen: ";
		temp << aMessage.getCompleteMessageSize();
		Logger::getInstance().log(temp.str());
		return false;
	} else if (written < (signed int) aMessage.getCompleteMessageSize()) {
		Logger::getInstance().log("Can't send message: less bytes writen then expected");
		return false;
	}
	return true;
}

void ClientConnection::setUsername(std::string anUsername) {
	username = anUsername;
}
std::string ClientConnection::getUsername() {
	return username;
}

void ClientConnection::setPassword(std::string aPassword) {
	password = aPassword;
}

std::string ClientConnection::getPassword() {
	return password;
}

bool ClientConnection::getWrite() {
	return writePermissions;
}

void ClientConnection::setWrite() {
	char IPbuf[100];
	inet_ntop(connectie.sa_family, get_in_addr(&connectie), IPbuf, 100);

	std::string IPstr1 = IPbuf, IPstr2 = IPbuf;
	int pos1, pos2;
	pos1 = IPstr1.find("."); //find first "."
	IPstr1 = IPstr1.substr(pos1 + 1);
	pos2 = IPstr1.find("."); //find second "."
	IPstr2 = IPstr2.substr(0, pos1 + pos2 + 2); //get first two IP parts

	if (strcmp(IPstr2.c_str(), Config::getInstance().getWriteIPRange().c_str()) == 0) {
		writePermissions = true;
	} else {
		writePermissions = false;
	}
}

void* ClientConnection::get_in_addr(struct sockaddr *sa) {
	if (sa->sa_family == AF_INET)
		return &(((struct sockaddr_in*) sa)->sin_addr);
	return &(((struct sockaddr_in6*) sa)->sin6_addr);
}

bool ClientConnection::getLogon() {
	return logon;
}

void ClientConnection::setLogon(bool aLogon) {
	logon = aLogon;
}
